package com.ljs.threadpooldemo.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步线程池配置
 */
@Configuration
@EnableAsync
@Data
public class AsynThredPoolConfig {
    /**
     * 线程池维护线程的最少数量，即使没有任务需要执行，也会一直存活
     */
    @Value("${poolconfig.corePoolSize}")
    private int corePoolSize;
    /**
     * 线程池维护线程的最大数量
     */
    @Value("${poolconfig.maxPoolSize}")
    private int maxPoolSize;
    /**
     * 缓存队列（阻塞队列）当核心线程数达到最大时，新任务会放在队列中排队等待执行
     */
    @Value("${poolconfig.queueCapacity}")
    private int queueCapacity;
    /**
     * 允许的空闲时间，当线程空闲时间达到keepAliveTime时，线程会退出，直到线程数量=corePoolSize
     */
    @Value("${poolconfig.keepAlive}")
    private int keepAlive;


    @Bean
    public TaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间（秒）
        threadPoolTaskExecutor.setKeepAliveSeconds(keepAlive);
        //线程名称
        threadPoolTaskExecutor.setThreadNamePrefix("test-thread-");
        // 设置拒绝策略rejection-policy：当pool已经达到max size的时候，如何处理新任务
        // CALL_RUNS:不在新线程中执行任务，二十由调用者所在的线程来执行
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化
        threadPoolTaskExecutor.initialize();
           return  threadPoolTaskExecutor;
    }
    /**
     * 拒绝策略RejectedExecutionHandler分为以下5种
     *
     * image-20210209142923446.png
     * AbortPolicy
     *
     * 该策略是线程池的默认策略。使用该策略时，如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常
     *
     * CallerRunsPolicy
     *
     * 使用此策略，如果添加到线程池失败，那么主线程会自己去执行该任务，不会等待线程池中的线程去执行。就像是个急脾气的人，我等不到别人来做这件事就干脆自己干。
     *
     * DiscardOldestPolicy
     *
     * 这个策略从字面上也很好理解，丢弃最老的。也就是说如果队列满了，会将最早进入队列的任务删掉腾出空间，再尝试加入队列。
     * 因为队列是队尾进，队头出，所以队头元素是最老的，因此每次都是移除对头元素后再尝试入队。
     *
     * DiscardPolicy
     *
     * 这个策略和AbortPolicy的slient版本，如果线程池队列满了，会直接丢掉这个任务并且不会有任何异常。
     *
     * 自定义
     *
     * 如果以上策略都不符合业务场景，那么可以自己定义一个拒绝策略，只要实现RejectedExecutionHandler接口，并且实现rejectedExecution方法就可以了。具体的逻辑就在rejectedExecution方法里去定义就OK了。
     *
     * 作者：大程子的技术成长路
     * 链接：https://www.jianshu.com/p/763ea6ce1da9
     * 来源：简书
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     */
}
